#ifndef __CCMGR__
#define __CCMGR__

#include <map>
#include "osfop.h"
#include "../../include/libstr.hpp"
#include "../../include/bitmap.h"

#define ENABLE_MEMORY_BLOCK_LOOKUP_TABLE

namespace xm
{
	template < class K, class V, class VFREE, class Hasher, size_t NUMCC >
	struct EzLruMap
	{
		enum
		{
			R_OKEY,
			R_ERR_PIN_FULL = -1,
			R_ERR_PIN_EXIST = -2,
			R_ERR_NOT_EXIST = -3,
			R_ERR_NOTHING_TO_REJECT = -4,
			R_ERR_FAIL = -100,
		};

		struct KeyNode
		{
			K			_k;
			KeyNode *	vnext;
			KeyNode *	vprev;

			KeyNode( const K & k ) : _k(k), vnext(0), vprev(0) {};

			bool operator < ( const KeyNode & r ) const
			{
				return _k < r._k;
			}

		} ;

		typedef std::map< KeyNode, V > _InLruMap;

		EzLruMap()
			: entFirst(0)
			, entLast(0)
		{

		}
		EzLruMap( VFREE& rfree )
			: entFirst(0)
			, entLast(0)
			, vfree(rfree)
		{

		}

		~EzLruMap()
		{
			Clear();
		}

		KeyNode *	entFirst;
		KeyNode *	entLast;
		_InLruMap	mapStore;
		VFREE		vfree; 

		typedef typename _InLruMap::iterator _InLruMapIt;

	protected:

		struct CcItem
		{
			BOOL		yes;
			_InLruMapIt itor;
			CcItem() : yes(false) {};
		};
		CcItem	_CcEnt[NUMCC];
		inline void CcUpdate( size_t idHash, _InLruMapIt& itor )
		{
			//printf( "CcUpdate: %08X\n", idHash );
			_CcEnt[idHash].yes = TRUE;
			_CcEnt[idHash].itor = itor;
		}
		inline void CcInvalid( const K & k )
		{
			size_t nHash = GetHash(k);
			CcItem& rItem = _CcEnt[nHash];
			if( !rItem.yes ) return ;
			if( !(rItem.itor->first._k == k) ) 
				return;
			//printf( "CcInvalid: %08X\n", nHash );
			_CcEnt[nHash].yes= FALSE;
		}
		inline void CcClear()
		{
			for( size_t i =0 ;i < NUMCC; ++ i )
				_CcEnt[i].yes = FALSE;
		}
		inline size_t GetHash( const K & k )
		{
			return Hasher()(k) % NUMCC;
		}

		inline BOOL CcQueryIt( const K & k, size_t& outHash, _InLruMapIt& itor )
		{
#if 0
			static size_t cTotal = 0, cHit = 0, cConflict = 0;
			printf( "t=%d, h=%d, c=%d\n", cTotal, cHit, cConflict );
			cTotal ++;
#endif
			outHash = GetHash(k);
			const CcItem& rItem = _CcEnt[outHash];
			if( !rItem.yes )
				return FALSE;
			if( !(rItem.itor->first._k == k) ) 
			{
#if 0
				cConflict ++;
#endif
				return FALSE;
			}
#if 0
			cHit ++;
#endif
			itor = rItem.itor;
			return TRUE;
		}
	public:

		inline LONG Remove( const K & k )
		{
			KeyNode kn(k);
			typename _InLruMap::iterator it = mapStore.find(kn);
			if( it == mapStore.end() )
				return R_ERR_NOT_EXIST;
#ifdef ENABLE_MEMORY_BLOCK_LOOKUP_TABLE
			CcInvalid( k );
#endif
			visit_remove( (KeyNode&)(it->first) );
			vfree( it->second );
			mapStore.erase( it );
			return R_OKEY;
		}
		inline LONG Remove( const K & k, V& v )
		{
			KeyNode kn(k);
			typename _InLruMap::iterator it = mapStore.find(kn);
			if( it == mapStore.end() )
				return R_ERR_NOT_EXIST;
#ifdef ENABLE_MEMORY_BLOCK_LOOKUP_TABLE
			CcInvalid( k );
#endif
			v = it->second;
			visit_remove( (KeyNode&)(it->first) );
			mapStore.erase( it );
			return R_OKEY;
		}
		inline size_t NumberInMap()
		{
			return mapStore.size();
		}
		inline LONG Pin( const K & k, V & v )
		{
			KeyNode kn(k);
			typename _InLruMap::iterator it = mapStore.find(kn);
			if( it != mapStore.end() )
				return R_ERR_PIN_EXIST;
			typename _InLruMap::value_type pr( kn, v );
			std::pair<typename _InLruMap::iterator, bool> ib = mapStore.insert( pr );
			if( ! ib.second ) return R_ERR_FAIL;
			it = ib.first;
#ifdef ENABLE_MEMORY_BLOCK_LOOKUP_TABLE
			CcUpdate( GetHash(k), it );
#endif
			visit_append( (KeyNode&)(it->first) );
			return R_OKEY;
		}
		inline LONG Pin( const K & k, V & v, V& rejectV )
		{
			KeyNode kn(k);
			typename _InLruMap::iterator it = mapStore.find(kn);
			if( it != mapStore.end() )
			{
				rejectV = it->second;
				it->second = v;
			}
			else
			{
				typename _InLruMap::value_type pr( kn, v );
				std::pair<typename _InLruMap::iterator, bool> ib = mapStore.insert( pr );
				if( ! ib.second ) return R_ERR_FAIL;
				it = ib.first;
			}
#ifdef ENABLE_MEMORY_BLOCK_LOOKUP_TABLE
			CcUpdate( GetHash(k), it );
#endif
			visit_append( (KeyNode&)(it->first) );
			return R_OKEY;
		}

		inline LONG Query( const K & k, V & val )
		{
			_InLruMapIt itor;
#ifdef ENABLE_MEMORY_BLOCK_LOOKUP_TABLE
			size_t nHash;
			if( !CcQueryIt(k,nHash,itor) )
			{
#endif
				KeyNode kn(k);
				itor = mapStore.find( kn );
				if( itor == mapStore.end() )
					return R_ERR_NOT_EXIST;
#ifdef ENABLE_MEMORY_BLOCK_LOOKUP_TABLE
				CcUpdate( nHash, itor );
			}
#endif
			visit_append( (KeyNode&)(itor->first) );
			val = itor->second;
			return R_OKEY;
		}

		inline void Clear()
		{
			CcClear();
			entLast = 0;
			entFirst = 0;
			typename _InLruMap::iterator it = mapStore.begin();
			for( ; it != mapStore.end(); ++ it )
				vfree( it->second );
			mapStore.clear();
		}
		inline LONG Reject( K& k, V& rVal )
		{
			if( !entLast ) return R_ERR_NOTHING_TO_REJECT;
			k = entLast->_k;
			return Remove( entLast->_k, rVal );
		}
	protected:
		inline void visit_remove( KeyNode & knode )
		{
			// cut
			KeyNode * prev = knode.vprev;
			KeyNode * next = knode.vnext;

			if( prev ) prev->vnext = next;
			if( next ) next->vprev = prev;

			if( entFirst == &knode ) entFirst = next;
			if( entLast == &knode ) entLast = prev;

			knode.vnext = 0;
			knode.vprev = 0;
		}
		inline void visit_append( KeyNode & knode )
		{
			visit_remove( knode );
			//////////////////////////////////////////////////////////////////////////
			// insert to head, if empty
			if( !entFirst )
			{
				entFirst = &knode;
				entLast = &knode;
				return;
			}

			// insert to head
			entFirst->vprev = &knode;
			knode.vnext = entFirst;
			entFirst = &knode;

			return;
		}

	};

	typedef UINT8*	byteptr;

	//struct MEMBLOCK : RefalbeImp
	//{
	//	BYTEPTR	GetMemPtr() { return (BYTEPTR)(this + 1); };
	//};

	typedef byteptr		MEMBLOCK;
	typedef MEMBLOCK	OMEMBLOCK;

	struct MEMBLOCK_FREE
	{
		void operator () ( OMEMBLOCK& block )
		{
			if( block ) delete [] block;
			block = NULL;
		}
	};

	byteptr MemPtr( OMEMBLOCK block )
	{
		return block;
	}

	VOID MemFreeBlock(OMEMBLOCK block )
	{
		if( block ) delete [] block;
	}
	VOID InitBlock( MEMBLOCK block )
	{
		
	}

	long CreateBlock( size_t cbBlock, OMEMBLOCK & rBlock )
	{
		MEMBLOCK pBlock = new UINT8[ cbBlock ];
		if( !pBlock ) return E_OUTOFMEMORY;
		InitBlock(pBlock);
		//new (pBlock) MEMBLOCK;
		rBlock = pBlock;
		return S_OK;
	}

	typedef UINT64	BSFOFFSET;
	typedef UINT64	FILEOFFSET;

#pragma pack(1)
	typedef struct _Token
	{
		LPCVOID		Owner;			// if Owner == NULL, it's a SwapFile Block;
		union {
			UINT64	Offset;
			UINT64	BlockId;
			UINT64	Any;
		} u;
	} cc_token_t;
#pragma pack()

	static inline bool operator < ( const cc_token_t & l, const cc_token_t& r )
	{
		if( l.Owner < r.Owner ) return true;
		if( l.Owner > r.Owner ) return false;
		INT64 diff = l.u.Offset - r.u.Offset;
		return diff < 0;
	}
	static inline bool operator == ( const cc_token_t & l, const cc_token_t& r )
	{
		if( l.Owner != r.Owner ) return false;
		if( l.u.Any != r.u.Any ) return false;
		return true;
	}

	static inline uint32_t MurmurHash1( const void * key, int len, uint32_t seed )
	{
		const unsigned int m = 0xc6a4a793;

		const int r = 16;

		unsigned int h = seed ^ (len * m);

		//----------

		const unsigned char * data = (const unsigned char *)key;

		while(len >= 4)
		{
			unsigned int k = *(unsigned int *)data;

			h += k;
			h *= m;
			h ^= h >> 16;

			data += 4;
			len -= 4;
		}

		//----------

		switch(len)
		{
		case 3:
			h += data[2] << 16;
		case 2:
			h += data[1] << 8;
		case 1:
			h += data[0];
			h *= m;
			h ^= h >> r;
		};

		//----------

		h *= m;
		h ^= h >> 10;
		h *= m;
		h ^= h >> 17;

		return h;
	} 

	struct KeyHasher
	{
		enum { HASH_NUM = 0x80000 };
		inline size_t operator () ( const cc_token_t& key ) const
		{
			return MurmurHash1(&key,sizeof(key),'RxMs')%HASH_NUM;
			//if( !key.Owner ) return (key.u.BlockId % HASH_NUM); 
			//size_t kOwner = (size_t)(key.Owner);
			//kOwner >>= 3;
			//kOwner ^= key.u.Any;
			////printf( "%d,%d -> %d\n", key.Owner, (size_t)key.u.Any, kOwner );
			//return kOwner;
		}
	};

	typedef EzLruMap< cc_token_t, OMEMBLOCK, MEMBLOCK_FREE, KeyHasher, KeyHasher::HASH_NUM >	BLOCK_CACHE_MAP;

	//struct XBitMap
	//{
	//	typedef std::vector<ULONG>	ULONGVEC;
	//	ULONGVEC			_buf;
	//	size_t				_bits;

	//	enum { BITS_PER_LONG = sizeof(ULONG)*8 };

	//	XBitMap() : _bits(0) {}

	//	inline size_t bits()
	//	{
	//		return _bits;
	//	}

	//	inline void clear()
	//	{
	//		_buf.clear();
	//		_bits = 0;
	//	}

	//	inline bool resize( size_t bits )
	//	{
	//		size_t numl = bits/BITS_PER_LONG + ((bits%BITS_PER_LONG)?1:0);
	//		_buf.resize( numl );
	//		_bits = bits;
	//		return true;
	//	}

	//	inline BOOL testbit( size_t idx )
	//	{
	//		if( idx >= _bits ) return FALSE;
	//		size_t li = idx/BITS_PER_LONG;
	//		size_t bi = idx%BITS_PER_LONG;
	//		return _buf[li] & (1<<bi);
	//	}
	//	inline void setbit( size_t idx, BOOL f )
	//	{
	//		size_t li = idx/BITS_PER_LONG;
	//		size_t bi = idx%BITS_PER_LONG;
	//		if( f ) _buf[li] |= (1<<bi);
	//		else _buf[li] &= ~(1<<bi);
	//	}
	//	inline BOOL find0( bool f, size_t & idx )
	//	{
	//		size_t li = _bits/BITS_PER_LONG;
	//		size_t bi = _bits%BITS_PER_LONG;
	//		for( size_t l = 0; l < li; ++ l )
	//		{
	//			if( _buf[l] == (ULONG)-1 ) continue; 
	//			ULONG ul = _buf[l];
	//			for( size_t i = 0; i < BITS_PER_LONG; ++ i )
	//			{
	//				if( ul & (1<<i) ) continue;
	//				idx = l * BITS_PER_LONG + i;
	//				return true;
	//			}
	//		}
	//		if( bi )
	//		{
	//			ULONG ul = _buf[li];
	//			for( size_t i = 0; i < bi; ++ i )
	//			{
	//				if( ul & (1<<i) ) continue;
	//				idx = li * BITS_PER_LONG + i;
	//				return true;
	//			}
	//		}

	//		return false;
	//	}

	//	// FIXME!
	//	BOOL findLast1( size_t & index, size_t piece = 2 )
	//	{
	//		piece = piece == 0 ? 1 : piece;
	//		size_t li = _buf.size();
	//		//size_t bi = _bits%BITS_PER_LONG;
	//		size_t bpp = li/piece;

	//		for( size_t l = 0; l < bpp; ++ l )
	//		{
	//			size_t idx = li - l - 1;
	//			if( _buf[idx] == 0 ) continue; 
	//			ULONG ul = _buf[l];
	//			for( size_t i = 0; i < BITS_PER_LONG; ++ i )
	//			{
	//				size_t ibit = BITS_PER_LONG - i - 1;
	//				if( ul & (1<<ibit) ) continue;
	//				index = l * BITS_PER_LONG + i;
	//				return true;
	//			}
	//		}
	//		return false;
	//		//if( _buf.empty() ) return FALSE;
	//		//size_t c = _buf.size() - 1;
	//		//PULONG  u = &_buf[0];
	//		//size_t i = 0;
	//		//for( ; i >=0 c && 0 == u[i]; ++ i );
	//		//if( i == _buf.size() ) return FALSE;
	//		//size_t bi = i*BITS_PER_LONG;
	//		//size_t uvb = _bits - bi;
	//		//uvb = uvb > BITS_PER_LONG ? BITS_PER_LONG : uvb;
	//		//ULONG v = _buf[i];
	//		//for( size_t t = 0; t < uvb; ++ t )
	//		//	if( v & (1<<t) ) index = bi + t;
	//		//return TRUE;
	//	}
	//};

	enum 
	{
		CC_NONSWAP_BLOCK = 0,
		CC_SWAP_BLOCK = 1,
	};

	template< size_t mSizeOfBlock = 0x1000 >
	class TCcStorage
	{
		BLOCK_CACHE_MAP	mBlockCache;
		ost::FastMutex	mMutex;
		size_t			mCacheBlocks;
		hfile_t			mStoageFile;
		bit_map_t		mBlockBitMap;
		size_t			mGrowCount;
		size_t			mUsedBlocks;
		SIZE_T			mFilesAlloced;
		SIZE_T			mFilesFreed;
		SIZE_T			mStoreCount;
		SIZE_T			mLoadCount;
		SIZE_T			mSlotFind;
		SIZE_T			mSlotHit;
		UINT64			mMaxBlockId;
	public:

		inline VOID UpdateMaxBlockId( UINT64 uBlockId )
		{
			mMaxBlockId = uBlockId > mMaxBlockId ? uBlockId : mMaxBlockId;
		}

		void IncFileAlloc()
		{
			mFilesAlloced ++;
		}
		void DecFileAlloc( size_t cFind, size_t cHit )
		{
			mSlotFind += cFind;
			mSlotHit += cHit;
			mFilesFreed ++;
			TryReduce();
		}

		TCcStorage( BOOL bCreateInTempDir = TRUE )
			: mCacheBlocks(0)
			, mStoageFile(INVALID_HFILE)
			, mGrowCount(0)
			, mUsedBlocks(0)
			, mStoreCount(0)
			, mLoadCount(0)
			, mSlotFind(0)
			, mSlotHit(0)
			, mMaxBlockId(0)
		{
			mMutex.init(0,0);
			if( bCreateInTempDir )
			{
//#ifdef _WIN32
				DWORD chPath = GetTempPathA( 0, NULL );
				if( !chPath ) return ;
				std::vector<CHAR> aTempDir(chPath+1);
				GetTempPathA( (DWORD)aTempDir.size(), &aTempDir[0] );
				std::string aFileName;
				tcs::xprintf( aFileName, "%s\\%X.dob", aTempDir.data(), GetCurrentProcessId() );
				//std::string aFileName = &aTempDir[0];
				//aFileName.append( szFileName );
//#else
//				std::string aFileName; // = &aTempDir[0];
//				tcs::xprintf( aFileName, "%s/proc-%d.bsf", RxHome(), getpid() );
//#endif
				Create( aFileName.c_str(), 0x10000 );
			}
		}

		~TCcStorage()
		{
			TryReduce();
			Close();
		}
		inline VOID TryReduce()
		{
#if (TARGET_OS==OS_WINDOWS)
#if 0
			char msg [128] = {};
			sprintf( msg, "cc=%d/%d, swp=%d/%d, ld/st=%d/%d, vf=%d/%d, h/f=%d/%d, maxb=%I64d, time=%d\n", mBlockCache.NumberInMap(), mCacheBlocks, mUsedBlocks, mBlockBitMap.bits(), mLoadCount, mStoreCount, mFilesFreed, mFilesAlloced, mSlotHit, mSlotFind, mMaxBlockId, clock() );
			SetConsoleTitleA( msg );
#endif
#endif
			return;
			//if( mMaxBlockId < 512 ) return ;
			//UINT64 uNowBlocks = mMaxBlockId+1;
			//UINT64 uNeedBlocks = 0;
			//size_t uLast1 = 0;
			//if( mBlockBitMap.findLast1(uLast1) )
			//	uNeedBlocks = (uLast1+1);

			//if( (uNeedBlocks<<1) < uNowBlocks )
			//{
			//	set_file_end( mStoageFile, uNeedBlocks*GetSizeOfBlock() );
			//	mMaxBlockId = uNeedBlocks;
			//}
		}
		// 64M
		long Create( LPCSTR aFileName, size_t aCacheBlocks = 0x4000, size_t aGrowBlocks = 0x1000 )
		{
			if( !aFileName || !aCacheBlocks || !aGrowBlocks )
				return E_INVALIDARG;
			hfile_t hFile = create_file( aFileName, true, true );
			if( hFile == INVALID_HFILE ) return E_FAIL;
			mStoageFile = hFile;
			mGrowCount = aGrowBlocks;
			mCacheBlocks = aCacheBlocks;
			return S_OK;
		}

		VOID Close()
		{
			if( mStoageFile != INVALID_HFILE ) 
				close_file( mStoageFile );
			mStoageFile = (INVALID_HFILE);
			mBlockCache.Clear();
			mBlockBitMap.clear();
			mCacheBlocks = (0);
			mGrowCount = (0);
		}

		size_t	size_of_chunk()
		{
			return mSizeOfBlock;
		}

		VOID	Reduce()
		{
#ifdef _DEBUG
			printf( "bsf::reduce();\n" );
#endif
		}

	protected:

		inline VOID	CodeBlockPage( OMEMBLOCK oBlock )
		{
#if TARGET_BITS==ARCH_32BIT
			UINT32* pU32 = (UINT32*)MemPtr(oBlock);
			for( size_t i = 0; i < mSizeOfBlock/sizeof(UINT32); ++ i )
			{
				pU32[i] ^= 0x19821201;
			}
#else
			UINT64* pU64 = (UINT64*)MemPtr(oBlock);
			for( size_t i = 0; i < mSizeOfBlock/sizeof(UINT64); ++ i )
			{
				pU64[i] ^= 0x1982120119821201LL;
			}
#endif
		}

		inline long StoreToStorage( UINT64 uRejOffset, OMEMBLOCK oBlock )
		{
			RFAILED( seek_file( mStoageFile, uRejOffset, SEEK_SET ) );
			CodeBlockPage( oBlock );
			size_t cbw = write_file( mStoageFile, MemPtr(oBlock), mSizeOfBlock );
			if( cbw != mSizeOfBlock ) return E_FAIL;
			mStoreCount ++;
			return S_OK;
		}
		inline long LoadFromStorage( UINT64 uOffset, OMEMBLOCK oBlock )
		{
			RFAILED( seek_file( mStoageFile, uOffset, SEEK_SET ) );
			size_t cbr = read_file( mStoageFile, MemPtr(oBlock), mSizeOfBlock );
			if( cbr != mSizeOfBlock ) return E_FAIL;
			CodeBlockPage( oBlock );
			mLoadCount ++;
			return S_OK;
		}

		inline long RejectBlock( OMEMBLOCK& rMemBlock )
		{
			OMEMBLOCK oBlock;

			cc_token_t uRejTok = {};
			LONG lr = mBlockCache.Reject( uRejTok, oBlock );
			if( lr < 0 ) return E_FAIL;

			// if a swap-block rejected, write-back to bsf
			if( !uRejTok.Owner )
			{
				UINT64 uBlockId = uRejTok.u.BlockId; 
				BOOL bUsaed = (uBlockId >= mBlockBitMap.bits() ) ? FALSE : mBlockBitMap.testbit((size_t)uBlockId);
				if(bUsaed)
				{
					UINT64 uRejOffset = uBlockId * mSizeOfBlock;
					RFAILED( StoreToStorage( uRejOffset, oBlock ) );
				}
			}
			rMemBlock = oBlock;
			return S_OK;
		}

		inline long MapNonSwapBlock( cc_token_t& rTok, OMEMBLOCK& oBlock )
		{
			LONG lr = ( mBlockCache.Query(rTok,oBlock) );
			if( lr >= 0 ) return S_OK;
			if( mBlockCache.NumberInMap() >= mCacheBlocks )
			{
				RFAILED( RejectBlock( oBlock ) );
			}
			else
			{
				RFAILED( CreateBlock( mSizeOfBlock, oBlock ) );
			}
			// pin to cache
			lr = mBlockCache.Pin( rTok, oBlock );
			if( lr < 0 ) return E_FAIL;

			// clear block
			memset( MemPtr(oBlock), 0, mSizeOfBlock );

			return S_OK;
		}
		inline long MapSwapBlock( cc_token_t& cmTok, OMEMBLOCK& oMemBlock, BOOL bNewBlock = FALSE )
		{
			OMEMBLOCK oBlock;
			if( mBlockCache.Query( cmTok, oBlock ) < 0 )
			{
				UINT64 uBlockId = cmTok.u.BlockId;
				BOOL bUsed = mBlockBitMap.testbit((size_t)uBlockId);

				if( mBlockCache.NumberInMap() >= mCacheBlocks )
				{
					long hr = RejectBlock( oBlock );
					if( FAILED(hr) ) return hr;
				}
				else
				{
					long hr = CreateBlock( mSizeOfBlock, oBlock );
					if( FAILED(hr) ) return hr;
				}
				//////////////////////////////////////////////////////////////////////////
				if( bUsed )
				{
					UINT64 uOffset = uBlockId * mSizeOfBlock;
					RFAILED( LoadFromStorage( uOffset, oBlock ) );
				}
				else
				{
					memset( MemPtr(oBlock), 0, mSizeOfBlock );
				}
				LONG lr = mBlockCache.Pin( cmTok, oBlock );
				if( lr < 0 ) return E_FAIL;
			}
			//////////////////////////////////////////////////////////////////////////
			oMemBlock = oBlock;
			return S_OK;
		}
		inline byteptr	AllocSwapBlock( cc_token_t & rTok )
		{
			ost::MutexScope _SYNC_(mMutex);
			UINT64 rBlockIndex = 0;
			if( FAILED( PreAllocSwapBlockAlways( rBlockIndex ) ) )
				return NULL;
			//printf( "PreAllocSwapBlockAlways return : %I64X\n", rBlockIndex );
			rTok.Owner = NULL;
			rTok.u.BlockId = rBlockIndex;
			OMEMBLOCK oBlock;
			if( FAILED( MapSwapBlock( rTok, oBlock, TRUE ) ) )
				return NULL;
			memset( MemPtr(oBlock), 0, mSizeOfBlock );
			MarkSwapBlockUsed( rBlockIndex, TRUE );
			return MemPtr(oBlock);
		}
		inline byteptr AllocNonSwapBlock( IN OUT cc_token_t & rTok )
		{
			ost::MutexScope _SYNC_(mMutex);
			OMEMBLOCK oBlock;
			if( FAILED( MapNonSwapBlock( rTok, oBlock ) ) )
				return NULL;
			return MemPtr(oBlock);
		}
	public:
		inline VOID Lock() 
		{
			mMutex.lock();
		}
		inline VOID Unlock()
		{
			mMutex.unlock();
		}
		
		inline long adjust_chunk_cache_room( size_t cCacheBlocks )
		{
			ost::MutexScope _SYNC_(mMutex);
			while( mBlockCache.NumberInMap() > cCacheBlocks )
			{
				OMEMBLOCK oBlock;
				RFAILED( RejectBlock( oBlock ) );
				MemFreeBlock(oBlock);
			}
			if( cCacheBlocks ) mCacheBlocks = cCacheBlocks;
			return S_OK;
		}
		
		inline byteptr	alloc_block( cc_token_t & rTok, ULONG uBlockType )
		{
			if( uBlockType == CC_SWAP_BLOCK )
				return AllocSwapBlock(rTok);
			else if( uBlockType == CC_NONSWAP_BLOCK )
				return AllocNonSwapBlock(rTok);
			return NULL;
		}

		inline long convert_to_nonswap_chunk( IN cc_token_t & rTok, const cc_token_t& rNewTok )
		{
			// Has been a non-swap-block
			RASSERT( !rTok.Owner, S_FALSE );
			RASSERT( rNewTok.Owner, E_FAIL );

			ost::MutexScope _SYNC_(mMutex);

			// remove from block-cache
			OMEMBLOCK obp;
			LONG lr = mBlockCache.Remove( rTok, obp);

			MarkSwapBlockUsed(rTok.u.BlockId,FALSE);

			OMEMBLOCK extp = 0;
			RFAILED( mBlockCache.Pin( rNewTok, obp, extp ) );
			MemFreeBlock(extp);

			rTok = rNewTok;

			return S_OK;
		}

		inline long convert_to_swap_chunk( IN OUT cc_token_t & rTok )
		{
			// Has been a swap-block
			RASSERT( rTok.Owner, S_FALSE );

			ost::MutexScope _SYNC_(mMutex);

			// alloc in bsf
			UINT64 rBlockIndex = 0;
			if( FAILED( PreAllocSwapBlockAlways( rBlockIndex ) ) )
				return E_OUTOFMEMORY;

			// remove exist block( none-sawp)
			// if none-swap-block not exists, return E_FAIL
			OMEMBLOCK obp;
			LONG lr = mBlockCache.Remove( rTok, obp);
			if( FAILED(lr) ) return E_FAIL;

			// convert to a swap-block token
			rTok.Owner = NULL;
			rTok.u.BlockId = rBlockIndex;

			// pin to cache
			OMEMBLOCK extp = 0;
			lr = mBlockCache.Pin( rTok, obp, extp );
			if( lr < 0 ) return E_FAIL;
			MemFreeBlock( extp );

			MarkSwapBlockUsed(rBlockIndex,TRUE);
			return S_OK;

		}

		inline long free_chunk( cc_token_t & rTok )
		{
			ost::MutexScope _SYNC_(mMutex);
			if( !rTok.Owner )
			{
				return MarkSwapBlockUsed( rTok.u.BlockId, FALSE );
			}
			else
			{
				// need not to free
				return S_OK;
			}
		}
		inline byteptr query_chunk( IN cc_token_t & rTok )
		{
			ost::MutexScope _SYNC_(mMutex);
			OMEMBLOCK oBlock;
			if( !rTok.Owner )
			{
				if( FAILED( MapSwapBlock( rTok, oBlock ) ) )
					return NULL;
			}
			else
			{
				if( mBlockCache.Query( rTok, oBlock ) < 0 )
					return NULL;
			}
			return MemPtr(oBlock);
		}

	protected:

		inline long MarkSwapBlockUsed( UINT64 rBlockIdx, bool bUsed )
		{
			if( rBlockIdx >= mBlockBitMap.bits() )
				return E_UNEXPECTED;
			if( bUsed ) ++ mUsedBlocks; else -- mUsedBlocks;
			if( bUsed ) UpdateMaxBlockId(rBlockIdx);
			mBlockBitMap.setbit((size_t)rBlockIdx,bUsed);
			return S_OK;
		}

		inline long PreAllocSwapBlockAlways( UINT64 & rBlockIdx )
		{
			size_t bidx = 0;
			if( mBlockBitMap.find0(false,bidx) )
			{
				rBlockIdx = bidx;
				return S_OK;
			}
			size_t cBits = mBlockBitMap.bits();
			mBlockBitMap.resize( cBits + mGrowCount );
			rBlockIdx = cBits;
			return S_OK;
		}
	};

	typedef TCcStorage<0x1000>	CcStorage;
};

static xm::CcStorage	ThisProcessCacheStorage;

static long STDAPICALLTYPE MssSetCacheSize( size_t cmCacheMemory )
{
	size_t cBlocks = cmCacheMemory/ThisProcessCacheStorage.size_of_chunk();
	return ThisProcessCacheStorage.adjust_chunk_cache_room(cBlocks);
}


#endif